package com.example.wx.dailyreport.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.wx.dailyreport.mapper.RoleMapper;
import com.example.wx.dailyreport.mapper.UserMapper;
import com.example.wx.dailyreport.pojo.*;
import com.example.wx.dailyreport.service.AuthorityService;
import com.example.wx.dailyreport.service.UserAuthorityService;
import com.example.wx.dailyreport.service.UserRoleService;
import com.example.wx.dailyreport.service.UserService;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hulinbo
 * @since 2020-07-28
 */
@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private UserAuthorityService userAuthorityService;

    @Autowired
    private AuthorityService authorityService;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private PasswordEncoder bCryptPasswordEncoder;

    @Override
    public User findByUsername(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(User::getUsername, username);
        return userMapper.selectOne(queryWrapper);
    }

    @Override
    public boolean updatePassword(User user) {
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(User::getUsername, user.getUsername());
        user.setUsername(null);
        return userMapper.update(user, updateWrapper) > 0;
    }

    @Override
    public boolean updateName(User user) {
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(User::getUsername, user.getUsername());
        user.setUsername(null);
        return userMapper.update(user, updateWrapper) > 0;
    }

    @Override
    public ReportRoles getUserClassInfo(String username) {
        return new ReportRoles(roleMapper.selectRolesByUsername(username), userMapper.selectUserHasRole(1l), userMapper.selectUserHasRole(2l));
    }

    @Override
    public int selectUserCount(User user, Long role_flag, Long authority_flag) {
        if (role_flag != null && role_flag > 0)
            authority_flag = null;
        return userMapper.selectUserCountBy(user, role_flag, authority_flag);
    }


    @Override
    public List<UserRoleAuthority> selectUserInPage(User user, Long role_flag, Long authority_flag, int page, int limit) {
        int skip = (page - 1) * limit;
        if (role_flag != null && role_flag > 0)
            authority_flag = null;
        return userMapper.selectUserBy(user, role_flag, authority_flag, skip, limit);
    }

    @Override
    public boolean updateUserRoleAuthority(Integer id, Integer[] roleids, Integer[] addAuthorities, Integer[] delAuthorities) {
        UpdateWrapper<UserRole> userRoleUpdateWrapper = new UpdateWrapper<>();
        userRoleUpdateWrapper.lambda().eq(UserRole::getUserId, id);
        userRoleService.remove(userRoleUpdateWrapper);
        if (ArrayUtils.isNotEmpty(roleids)) {
            List<UserRole> addUserRole = new ArrayList<>();
            for (int roleid : roleids) {
                UserRole userRole = new UserRole();
                userRole.setUserId(id);
                userRole.setRoleId(roleid);
                addUserRole.add(userRole);
            }
            userRoleService.saveBatch(addUserRole);
        }

        UpdateWrapper<UserAuthority> userAuthorityUpdateWrapper = new UpdateWrapper<>();
        userAuthorityUpdateWrapper.lambda().eq(UserAuthority::getUserId, id);
        userAuthorityService.remove(userAuthorityUpdateWrapper);
        List<UserAuthority> addUserAuthority = new ArrayList<>();
        if (ArrayUtils.isNotEmpty(addAuthorities))
            for (int authority : addAuthorities) {
                UserAuthority userAuthority = new UserAuthority();
                userAuthority.setUserId(id);
                userAuthority.setAuthorityId(authority);
                userAuthority.setProperties(1);
                addUserAuthority.add(userAuthority);
            }
        if (ArrayUtils.isNotEmpty(delAuthorities))
            for (int authority : delAuthorities) {
                UserAuthority userAuthority = new UserAuthority();
                userAuthority.setUserId(id);
                userAuthority.setAuthorityId(authority);
                userAuthority.setProperties(0);
                addUserAuthority.add(userAuthority);
            }
        userAuthorityService.saveBatch(addUserAuthority);

        return true;
    }

    @Override
    public Map<String, Object> getAuthoritiesByUserId(Integer id) {
        Map<String, Object> map = new LinkedHashMap<>();
        List<Authority> authorities = authorityService.list();
        List<Authority> residue = new LinkedList<>(authorities);

        QueryWrapper<UserAuthority> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UserAuthority::getUserId, id);
        List<UserAuthority> userAuthorities = userAuthorityService.list(queryWrapper);

        Map<Integer, Authority> allAuthorityMap = new HashMap<>();

        List<Authority> addAuthorities = new ArrayList<>();
        List<Authority> delAuthorities = new ArrayList<>();

        if (!CollectionUtils.isEmpty(authorities))
            for (Authority authority : authorities) {
                if (isExist(userAuthorities, authority)) {
                    allAuthorityMap.put(authority.getId(), authority);
                    residue.remove(authority);
                }
            }
        if (!CollectionUtils.isEmpty(userAuthorities))
            for (UserAuthority userAuthority : userAuthorities) {
                if (userAuthority.getProperties() == 1)
                    addAuthorities.add(allAuthorityMap.get(userAuthority.getAuthorityId()));
                else
                    delAuthorities.add(allAuthorityMap.get(userAuthority.getAuthorityId()));
            }

        map.put("residue", residue);
        map.put("add", addAuthorities);
        map.put("del", delAuthorities);

        return map;
    }


    private boolean isExist(List<UserAuthority> list, Authority authority) {
        if (!CollectionUtils.isEmpty(list))
            for (UserAuthority userAuthority : list) {
                if (userAuthority.getAuthorityId().equals(authority.getId()))
                    return true;
            }
        return false;
    }

    @Override
    public boolean save(User entity) {
        entity.setPassword(bCryptPasswordEncoder.encode(entity.getPassword()));
        return super.save(entity);
    }
}
